/*
 * 	Flan.Zeng 2011-2016	http://git.oschina.net/signup?inviter=flan
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.flan.stock.net;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.List;

import com.flan.stock.bean.Stock;
import com.flan.stock.utils.Constant;
import com.flan.stock.utils.Log;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

/**
 * 进行Socket通信的客户端连接类
 * 只进行原始数据的发送与接收操作
 * @author flan
 * @date   2015年12月24日
 */
public class StockDataSource extends Thread{
	
	private static final String tag = "StockDataSource";
	private Selector selector;
	private SocketChannel channel;
	private ByteBuffer readBuffer;
	private Handler	serviceHandler;	//UI线程中的handler
	
	private boolean isRunning = true;
	
	private String ip;
	private int port;
	
	public StockDataSource(String ip, int port) {
		super();
		this.readBuffer = ByteBuffer.allocate(8056);
		this.ip = ip;
		this.port = port;
	}
	
	/**
	 * 传入UI线程中的handler，请求处理完成后通知UI线程更新数据
	 * @param serviceHandler
	 */
	public void setServiceHandler(Handler serviceHandler) {
		this.serviceHandler = serviceHandler;
	}

	/**
	 * 获取股票排行数据
	 * @param recordNum
	 */
	public void getStockRank(Bundle bundle){
		
		ByteBuffer buffer = ByteBuffer.allocate(48);
		
		buffer.putInt(Constant.SERVICE_QUOTATION_RANK_REQUEST);
		buffer.putInt(bundle.getInt("flag"));
		
		buffer.putInt(bundle.getInt("start"));
		buffer.putInt(bundle.getInt("wantnum"));
		buffer.putInt(bundle.getInt("colunm"));
		buffer.putInt(bundle.getInt("desc"));
		
		buffer.flip();
		try {
			channel.write(buffer);
			Log.d(tag, "NIO --> 向服务器发出写操作！");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 关闭与服务器的连接
	 */
	public void close(){
		isRunning = false;
	}

	@Override
	public void run() {
		
		initClient();
		startClient();	//该方法会在内部循环监听
		Log.d(tag, "通信线程启动成功！");
	}
	
	/**
	 * 初始化与服务器的连接通道
	 * @throws IOException
	 */
	private void initClient(){
		
		try {
			// 获得一个Socket通道 
			channel = SocketChannel.open();
			// 设置通道为非阻塞
			channel.configureBlocking(false);
			// 获得一个通道管理器
			selector = Selector.open();
			
			// 客户端连接服务器,其实方法执行并没有实现连接，需要在listen（）方法中调  
			//用channel.finishConnect();才能完成连接
			channel.connect(new InetSocketAddress(ip, port));
			channel.register(selector, SelectionKey.OP_CONNECT);
			
		} catch (ClosedChannelException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 启动监听操作
	 */
	private void startClient(){
		try {
			while (isRunning) {
				
				selector.select();
				Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
				
				while (iterator.hasNext()) {
					SelectionKey selectionKey = iterator.next();
					iterator.remove();// 删除已选的key,以防重复处理
					
					if(selectionKey.isConnectable()){	// 连接事件发生
						channel = (SocketChannel) selectionKey.channel();
						
						// 如果正在连接，则完成连接
						if(channel.isConnectionPending()){
							channel.finishConnect();
						}
						channel.configureBlocking(false);
						channel.register(selector, SelectionKey.OP_READ);
					}else if(selectionKey.isReadable()){
						read(selectionKey);
					}
				}
			}
			
			channel.close();	//关闭通道
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	private void read(SelectionKey key) throws IOException{
		
		// 服务器可读取消息:得到事件发生的Socket通道
		SocketChannel channel = (SocketChannel) key.channel();
		
		readBuffer.clear();
		channel.read(readBuffer);
		int position = readBuffer.position();
		System.out.println(position);
		readBuffer.flip();
		
		int flag = readBuffer.getInt(0);
		
		ByteArrayInputStream bios = new ByteArrayInputStream(readBuffer.array(),4,position);	//一个int值在readBuffer占4个byte
		ObjectInputStream ois = new ObjectInputStream(bios);
		
		try {
			
			List<Stock> stocks = (List<Stock>) ois.readObject();
			/*if(stocks != null){
				for(Stock s : stocks){
					System.out.println("=========>>股票名称："+s.getName()+" 股票代码："+s.getCode()+ " 现价："+s.getNowPrice());
				}
			}*/
			
			Log.d(tag, "NIO --> 成功读取服务器传回的数据！");
			Message msg = new Message();
			msg.what = Constant.SERVICE_QUOTATION_RANK_REQUEST;
			msg.arg1 = flag;	//原样返回的标识位
			msg.obj = stocks;
			serviceHandler.sendMessage(msg);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}











